package com.cskaoyan.polymorphism;

/*
       Java语言中的多态指什么呢？ “同一个对象”的行为，在不同的时刻或条件下，表现出不同的效果。

       发生多态的条件：
       a. 继承
       b. 方法覆盖
       c. 父类引用指向子类对象


       多态中的成员访问特征
       成员变量
         编译看左边，运行看左边
       成员方法(多态效果)
        编译看左边，运行看右边

 解释：
      1. 编译看左边： 父类引用指向子类对象，此时编看左边是在说，
                      通过引用变量可以访问到的成员的范围，是由引用类型来决定的

          a. 迄今为止，我们是怎么去访问一个对象？我们都是通过一个中间人即引用变量，间接访问堆上对象
          b. 也就是说，只有通过引用变量，我才能访问到堆上的对象

      举例：
      1). 我们如果把对象，当成我们的一台电视机，对于电视机而言，我们只能使用，遥控器去操作电视机

      2). 这也就意味着，遥控器提供了什么样的功能，那我们只能使用，遥控器提供的功能，操作电视机
         此时即使电视机提供了很多功能可以使用，但是如果遥控器提供了，极其有限的功能

      3). 这意味着，我们可以使用的电视机的功能，被遥控器给限制了

      所以，回到java程序，访问对象的时候，引用变量，就是我们用来操作对象的"遥控器"，所以引用变量的类型
      决定了，可以访问到的成员的范围。

      2. 对于成员变量，运行看左边
      一个对象 属性(成员变量) 和 行为，一个对象的属性(成员变量表示)，表示了一对象的外貌
      在多态中，此时对于子类对象而言，把子类对象赋值给父类类型的引用，就相当于给子类对象
      披上了一个父类类型马甲， 因此，该子类对象看起来，就是一个父类对象(外貌特征，
      表现出的就应该是父类的外貌特征)

     3.  对于成员方法的，运行(结果)看 右边(多态)
        就是说对于成员方法而言，通过引用变量，实际访问到的行为(方法), 是由引用实际指向的对象来决定的



 */
public class Demo1Basic {

    public static void main(String[] args) {
        // 测试多态的效果
        //testPoly();

        // 测试多态成员的访问
        //testMemberAccess();
        // 父类类型的引用变量
        PolyFather polyFather;
        // 编译看左边
        polyFather = new FirstPolySon();

        // 通过父类引用，无法访问到，子类自己定义成员
        //polyFather.son();

        FirstPolySon first = new FirstPolySon();
        // 通过子类应用，才能访问到，子类自己定义的成员
        first.son();

        // 总结一下，通过引用变量，到底能访问到哪些成员？
        //   只和引用变量的类型有关系，而和引用变量所指向的实际类型
    }

    private static void testMemberAccess() {
        // 多态的成员访问特征(成员变量，成员方法)
        PolyFather polyFather;

        polyFather = new FirstPolySon();
        //  通过父类引用访问父类子类定义的同名成员变量值，访问的是父类定义的成员变量值
        System.out.println(polyFather.value); // 100
        // 多态效果
        polyFather.testPolymorphism();

        polyFather = new SecondPolySon();
        //  通过父类引用访问父类子类定义的同名成员变量值，访问的是父类定义的成员变量值
        System.out.println(polyFather.value); // 100
        // 多态效果
        polyFather.testPolymorphism();
    }

    private static void testPoly() {
        // 父类引用指向子类对象
        // 同一个引用变量
//        PolyFather polyFather;
//
//        // 多态的效果
//        polyFather = new FirstPolySon();
//        // 父类引用指向FirstPolySon子类对象
//        polyFather.testPolymorphism();
//
//        polyFather = new SecondPolySon();
//        // 父类引用指向SecondPolySon子类对象
//        polyFather.testPolymorphism();

        PolyFather polyFather = new PolyFather();
        testPolyMorphism(polyFather);

        PolyFather firstPolySon = new FirstPolySon();
        testPolyMorphism(firstPolySon);

        PolyFather secondPolySon = new SecondPolySon();
        testPolyMorphism(secondPolySon);

        // 可以把一个子类类型的引用变量值 赋值 给父类类型的引用变量值
        PolyFather father = secondPolySon;
    }
    /*
          多态的效果
     */
    public static void testPolyMorphism(PolyFather polyFather) {
        polyFather.testPolymorphism();
    }


}

class PolyFather {
    int value = 100;
    public void testPolymorphism() {
        System.out.println("testPolymorphism in father ");
    }
}
class FirstPolySon extends PolyFather {

    int value = 200;

    @Override
    public void testPolymorphism() {
        System.out.println("testPolymorphism in first son");
    }
    // 子类自己定义的方法，父类中未定义
    public void son() { }

}

class SecondPolySon extends PolyFather {

    int value = 300;

    @Override
    public void testPolymorphism() {
        System.out.println("testPolymorphism in second son");
    }

}